﻿unit common;

interface

uses
  Winapi.Windows, Winapi.ShellAPI, System.SysUtils, Winapi.IpTypes,
  Winapi.IpHlpApi, Winapi.WinSock2, System.Generics.Collections,
  System.Variants,
  ActiveX, ComObj, System.Classes, IdGlobal, idStack, Vcl.Dialogs;

const
  maxClientPoolSize = 32;
  // 1M时候，速度5.7MB/s
  sliceLength: uint64 = 1024 * 1024;
  slicesOfBlock: uint64 = 16;
  bufferLength = 32;
  InfoCastPort = 8888;
  ServerFileServicePort = 8887;
  infoServicePort = 8886;
  ClientFileServicePort = 8884;
  multicastGroup = 'ff02::e1f1:4a05:72a0:5f11:e000';
  magicString = 'ELFLYAOSFILETRANS';
  readyString = 'READY';
  serverString = 'SERVER';
  aliveString = 'ALIVE';
  testString = 'TEST';
  testOKString = 'TEST OK';
  fileInfoString = 'INFO';
  addString = 'ADD';
  whereString = 'WHERE';
  atString = 'AT';
  hashString = 'HASH';
  completeString = 'COMPLETE';
  BlockString = 'BLOCK';
  errorString = 'ERROR';

type
  TFileInfo = record
    serverFileName: string;
    fileName: string;
    size: uint64;
    hash: string;
    where: TList<integer>;
  end;

  TIPv6Card = record
    CardName: string;
    IPv6: string;
  end;

  TFileBlock = record
    length: int32;
    buffer: TBytes;
    hash: uint32;
  end;

var
  IPv6CardList: TList<TIPv6Card>;
  FileInfo: TFileInfo;
  FilePath: string;
  ServerIP: string;
  localIP: string;
  totalSlice: int32;
  commandList: TStringList;
  castCommandList: TStringList;

procedure randomArray(var a: TArray<uint32>; l: uint32);

function FormatNumberWithCommas(Value: Int64): string;

function GetCPUFeatures: TList<string>;

function NowTimeToString: string;

function SwapEndian(Value: uint32): uint32;

function EnumIPv6Card: TList<TIPv6Card>;

var
  HashData: function(v: TIdBytes; l: int32): uint32;
  CPUFeaturesList: TList<string>;

implementation

uses
  System.hash, WbemScripting_TLB, idhash, idHashCRC, crc;

procedure randomArray(var a: TArray<uint32>; l: uint32);
begin
  for var i := l - 1 downto 1 do
  begin
    var
    j := random(i + 1); // 0..i
    var
    t := a[i];
    a[i] := a[j];
    a[j] := t;
  end;
end;

function FormatNumberWithCommas(Value: Int64): string;
var
  s: string;
  i, len: integer;
begin
  s := Value.ToString;
  len := length(s);
  Result := '';

  for i := 1 to len do
  begin
    // 从右向左每3位插入逗号
    if (i > 1) and ((len - i + 1) mod 3 = 0) then
      Result := Result + ',';

    Result := Result + s[i];
  end;
end;

procedure CPUIDCall(out a: uint32; out B: uint32; out C: uint32; out D: uint32);
asm
  { x86: eax, edx, ecx, mem }
  { x64: rcx, rdx, r8, r9 }
  {$IFDEF CPUX86}
  push    esi
  push    edi
  push    ebp
  push    ebx
  mov     esi, eax // A
  mov     edi, edx // B
  mov     ebp, ecx // C
  mov     eax, [esi]
  XOR     ebx, ebx
  mov     ecx, [ebp]
  XOR     edx, edx
  cpuid
  mov     [esi], eax
  mov     [edi], ebx
  mov     [ebp], ecx
  mov     [D], edx
  pop     ebx
  pop     ebp
  pop     edi
  pop     esi
  {$ELSE}
  push    r10
  push    r11
  push    rbx
  mov     r10, rcx // A
  mov     r11, rdx // B
  // [r10] = A, [r11] = B, [r8] = C, [r9] = D
  mov     eax, dword ptr[r10]
  XOR     ebx, ebx
  mov     ecx, dword ptr[r8]
  XOR     edx, edx
  cpuid
  mov     dword ptr[r10], eax
  mov     dword ptr[r11], ebx
  mov     dword ptr[r8], ecx
  mov     dword ptr[r9], edx
  pop     rbx
  pop     r11
  pop     r10
  {$ENDIF}
end;

function GetCPUFeatures: TList<string>;
begin
  Result := TList<string>.Create;
  var
    a: uint32 := 1;
  var
    B, D: uint32;
  var
    C: uint32 := 0;

  CPUIDCall(a, B, C, D);

  // 常用指令集检测
  if (D and (1 shl 4)) <> 0 then
    Result.add('TSC');
  if (D and (1 shl 8)) <> 0 then
    Result.add('CX8');
  if (D and (1 shl 15)) <> 0 then
    Result.add('CMOV');
  if (D and (1 shl 23)) <> 0 then
    Result.add('MMX');
  if (D and (1 shl 25)) <> 0 then
    Result.add('SSE');
  if (D and (1 shl 26)) <> 0 then
    Result.add('SSE2');

  if (C and (1 shl 0)) <> 0 then
    Result.add('SSE3');
  if (C and (1 shl 1)) <> 0 then
    Result.add('PCLMUL');
  if (C and (1 shl 9)) <> 0 then
    Result.add('SSSE3');
  if (C and (1 shl 12)) <> 0 then
    Result.add('FMA');
  if (C and (1 shl 13)) <> 0 then
    Result.add('CX16');
  if (C and (1 shl 19)) <> 0 then
    Result.add('SSE4.1');
  if (C and (1 shl 20)) <> 0 then
    Result.add('SSE4.2');
  if (C and (1 shl 22)) <> 0 then
    Result.add('MOVBE');
  if (C and (1 shl 23)) <> 0 then
    Result.add('POPCNT');
  if (C and (1 shl 25)) <> 0 then
    Result.add('AES');
  if (C and (1 shl 28)) <> 0 then
    Result.add('AVX');
  if (C and (1 shl 30)) <> 0 then
    Result.add('RDRAND');

  a := 0;
  C := 0;
  CPUIDCall(a, B, C, D);

  if a >= 7 then
  begin
    a := 7;
    C := 0;
    CPUIDCall(a, B, C, D);

    {
      EBX Bit 00: FSGSBASE. Supports RDFSBASE/RDGSBASE/WRFSBASE/WRGSBASE if 1.
      Bit 01: IA32_TSC_ADJUST MSR is supported if 1.
      Bit 02: SGX.
      Bit 03: BMI1.
      Bit 04: HLE.
      Bit 05: AVX2. Supports Intel® Advanced Vector Extensions 2 (Intel® AVX2) if 1.
      Bit 06: FDP_EXCPTN_ONLY. x87 FPU Data Pointer updated only on x87 exceptions if 1.
      Bit 07: SMEP. Supports Supervisor Mode Execution Protection if 1.
      Bit 08: BMI2.
      Bit 09: Supports Enhanced REP MOVSB/STOSB if 1.
      Bit 10: INVPCID.
      Bit 11: RTM.
      Bit 12: RDT-M. Supports Intel® Resource Director Technology (Intel® RDT) Monitoring capability if 1.
      Bit 13: Deprecates FPU CS and FPU DS values if 1.
      Bit 14: Intel® Memory Protection Extensions.
      Bit 15: RDT-A. Supports Intel® Resource Director Technology (Intel® RDT) Allocation capability if 1.
      Bit 16: AVX512F.
      Bit 17: AVX512DQ.
      Bit 18: RDSEED.
      Bit 19: ADX.
      Bit 20: SMAP.
      Bit 21: AVX512_IFMA.
      Bit 22: Reserved.
      Bit 23: CLFLUSHOPT.
      Bit 24: CLWB.
      Bit 25: Intel Processor Trace.
      Bit 26: AVX512PF. (Intel® Xeon Phi™ only.)
      Bit 27: AVX512ER. (Intel® Xeon Phi™ only.)
      Bit 28: AVX512CD.
      Bit 29: SHA.
      Bit 30: AVX512BW.
      Bit 31: AVX512VL.
    }
    if (B and (1 shl 3)) <> 0 then
      Result.add('BMI1');
    if (B and (1 shl 5)) <> 0 then
      Result.add('AVX2');
    if (B and (1 shl 8)) <> 0 then
      Result.add('BMI2');
    if (B and (1 shl 18)) <> 0 then
      Result.add('RDSEED');
    if (B and (1 shl 19)) <> 0 then
      Result.add('ADX');
    if (B and (1 shl 29)) <> 0 then
      Result.add('SHA');

    {
      ECX Bit 00: PREFETCHWT1. (Intel® Xeon Phi™ only.)
      Bit 01: AVX512_VBMI.
      Bit 02: UMIP. Supports user-mode instruction prevention if 1.
      Bit 03: PKU. Supports protection keys for user-mode pages if 1.
      Bit 04: OSPKE. If 1, OS has set CR4.PKE to enable protection keys (and the RDPKRU/WRPKRU instructions).
      Bit 05: WAITPKG.
      Bit 06: AVX512_VBMI2.
      Bit 07: CET_SS. Supports CET shadow stack features if 1. Processors that set this bit define bits 1:0
      of the IA32_U_CET and IA32_S_CET MSRs. Enumerates support for the following MSRs: IA32_INTERRUPT_SPP_TABLE_ADDR, IA32_PL3_SSP, IA32_PL2_SSP, IA32_PL1_SSP, and IA32_PL0_SSP.
      Bit 08: GFNI.
      Bit 09: VAES.
      Bit 10: VPCLMULQDQ.
      Bit 11: AVX512_VNNI.
      Bit 12: AVX512_BITALG.
      Bit 13: TME_EN. If 1, the following MSRs are supported: IA32_TME_CAPABILITY, IA32_TME_ACTIVATE, IA32_TME_EXCLUDE_MASK, and IA32_TME_EXCLUDE_BASE.
      Bit 14: AVX512_VPOPCNTDQ.
      Bit 15: Reserved.
      Bit 16: LA57. Supports 57-bit linear addresses and five-level paging if 1.
      Bits 21-17: The value of MAWAU used by the BNDLDX and BNDSTX instructions in 64-bit mode.
      Bit 22: RDPID and IA32_TSC_AUX are available if 1.
      Bit 23: KL. Supports Key Locker if 1.
      Bit 24: BUS_LOCK_DETECT. If 1, indicates support for bus lock debug exceptions.
      Bit 25: CLDEMOTE. Supports cache line demote if 1.
      Bit 26: Reserved.
      Bit 27: MOVDIRI. Supports MOVDIRI if 1.
      Bit 28: MOVDIR64B. Supports MOVDIR64B if 1.
      Bit 29: ENQCMD: Supports Enqueue Stores if 1.
      Bit 30: SGX_LC. Supports SGX Launch Configuration if 1.
      Bit 31: PKS. Supports protection keys for supervisor-mode pages if 1
    }

    {
      EDX Bit 00: Reserved.
      Bit 01: SGX-KEYS. If 1, Attestation Services for Intel® SGX is supported.
      Bit 02: AVX512_4VNNIW. (Intel® Xeon Phi™ only.)
      Bit 03: AVX512_4FMAPS. (Intel® Xeon Phi™ only.)
      Bit 04: Fast Short REP MOV.
      Bit 05: UINTR. If 1, the processor supports user interrupts.
      Bits 07-06: Reserved.
      Bit 08: AVX512_VP2INTERSECT.
      Bit 09: SRBDS_CTRL. If 1, enumerates support for the IA32_MCU_OPT_CTRL MSR and indicates that
      its bit 0 (RNGDS_MITG_DIS) is also supported.
      Bit 10: MD_CLEAR supported.
      Bit 11: RTM_ALWAYS_ABORT. If set, any execution of XBEGIN immediately aborts and transitions to
      the specified fallback address.
      Bit 12: Reserved.
      Bit 13: If 1, RTM_FORCE_ABORT supported. Processors that set this bit support the
      TSX_FORCE_ABORT MSR. They allow software to set TSX_FORCE_ABORT[0] (RTM_FORCE_ABORT).
      Bit 14: SERIALIZE.
      Bit 15: Hybrid. If 1, the processor is identified as a hybrid part. If CPUID.0.MAXLEAF ≥ 1AH and
      CPUID.1A.EAX ≠ 0, then the Native Model ID Enumeration Leaf 1AH exists.
      Bit 16: TSXLDTRK. If 1, the processor supports Intel TSX suspend/resume of load address tracking.
      Bit 17: Reserved.
      Bit 18: PCONFIG.
      Bit 19: Architectural LBRs. If 1, indicates support for architectural LBRs.
      Bit 20: CET_IBT. Supports CET indirect branch tracking features if 1. Processors that set this bit
      define bits 5:2 and bits 63:10 of the IA32_U_CET and IA32_S_CET MSRs.
      Bit 21: Reserved.
      Bit 22: AMX-BF16. If 1, the processor supports tile computational operations on bfloat16 numbers.
      Bit 23: AVX512_FP16.
      Bit 24: AMX-TILE. If 1, the processor supports tile architecture.
      Bit 25: AMX-INT8. If 1, the processor supports tile computational operations on 8-bit integers.
      Bit 26: Enumerates support for indirect branch restricted speculation (IBRS) and the indirect branch
      predictor barrier (IBPB). Processors that set this bit support the IA32_SPEC_CTRL MSR and the
      IA32_PRED_CMD MSR. They allow software to set IA32_SPEC_CTRL[0] (IBRS) and
      IA32_PRED_CMD[0] (IBPB).
      Bit 27: Enumerates support for single thread indirect branch predictors (STIBP). Processors that set
      this bit support the IA32_SPEC_CTRL MSR. They allow software to set IA32_SPEC_CTRL[1] (STIBP).
      Bit 28: Enumerates support for L1D_FLUSH. Processors that set this bit support the
      IA32_FLUSH_CMD MSR. They allow software to set IA32_FLUSH_CMD[0] (L1D_FLUSH).
      Bit 29: Enumerates support for the IA32_ARCH_CAPABILITIES MSR.
      Bit 30: Enumerates support for the IA32_CORE_CAPABILITIES MSR.
      IA32_CORE_CAPABILITIES is an architectural MSR that enumerates model-specific features. In general, a bit being set in this MSR indicates that a model-specific feature is supported; software should
      consult CPUID family/model/stepping to determine the behavior of these enumerated features, as
      that behavior may differ on different processor models. Some bits in the MSR enumerate features
      with behavior that is consistent across processor models (and for which consultation of CPUID family/model/stepping is not necessary); such bits are identified explicitly in the documentation of the
      IA32_CORE_CAPABILITIES MSR.
      Bit 31: Enumerates support for Speculative Store Bypass Disable (SSBD). Processors that set this bit
      support the IA32_SPEC_CTRL MSR. They allow software to set IA32_SPEC_CTRL[2] (SSBD).
    }
    {
      A := 7; C := 1;
      CPUIDCall(A, B, C, D);
    }
    {
      EAX This field reports 0 if the sub-leaf index, 1, is invalid.
      Bit 00: SHA512. If 1, supports the SHA512 instructions.
      Bit 01: SM3. If 1, supports the SM3 instructions.
      Bit 02: SM4. If 1, supports the SM4 instructions.
      Bit 03: RAO-INT. If 1, supports the RAO-INT instructions.
      Bit 04: AVX-VNNI. AVX (VEX-encoded) versions of the Vector Neural Network Instructions.
      Bit 05: AVX512_BF16. Vector Neural Network Instructions supporting bfloat16 inputs and conversion instructions from IEEE single precision.
      Bit 06: LASS. If 1, supports Linear Address Space Separation.
      Bit 07: CMPCCXADD. If 1, supports the CMPccXADD instruction.
      Bit 08: ArchPerfMonExt. If 1, supports ArchPerfMonExt. When set, indicates that the Architectural
      Performance Monitoring Extended Leaf (EAX = 23H) is valid.
      Bit 09: Reserved.
      Bit 10: If 1, supports fast zero-length MOVSB.
      Bit 11: If 1, supports fast short STOSB.
      Bit 12: If 1, supports fast short CMPSB, SCASB.
      Bits 16-13: Reserved.
      Bit 17: FRED. If 1, supports Flexible Return and Event Delivery and the architectural state (MSRs)
      defined by FRED. Any Intel processor that enumerates support for FRED transitions will also enumerate support for LKGS.
      Bit 18: LKGS. If 1, supports the LKGS (load into IA32_KERNEL_GS_BASE) instruction.
      Bit 19: WRMSRNS. If 1, supports the WRMSRNS instruction.
      Bit 20: NMI_SRC. If 1, supports NMI-source reporting.
      Bit 21: AMX-FP16. If 1, the processor supports tile computational operations on FP16 numbers.
      Bit 22: HRESET. If 1, supports history reset and the IA32_HRESET_ENABLE MSR. When set, indicates
      that the Processor History Reset Leaf (EAX = 20H) is valid.
      Bit 23: AVX-IFMA. If 1, supports the AVX-IFMA instructions.
      Bits 25-24: Reserved.
      Bit 26: LAM. If 1, supports Linear Address Masking.
      Bit 27: MSRLIST. If 1, supports the RDMSRLIST and WRMSRLIST instructions and the IA32_BARRIER
      MSR.
      Bits 29-28: Reserved.
      Bit 30: INVD_DISABLE_POST_BIOS_DONE. If 1, supports INVD execution prevention after BIOS Done.
      Bit 31: MOVRS.
      EBX This field reports 0 if the sub-leaf index, 1, is invalid; otherwise it is reserved.
      Bit 00: Enumerates the presence of the IA32_PPIN and IA32_PPIN_CTL MSRs. If 1, these MSRs are
      supported.
      Bit 01: PBNDKB. If 1, supports the PBNDKB instruction and enumerates the existence of the
      IA32_TSE_CAPABILITY MSR.
      Bits 31-02: Reserved.
    }
  end;
end;

function NowTimeToString: string;
begin
  // 使用 Now 函数获取当前日期时间
  Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now);
end;

function SwapEndian(Value: uint32): uint32;
asm
  {$IFDEF X86}
  { EAX = data }
  bswap eax
  {$ELSE}
  { RCX = data }
  mov eax, ecx
  bswap eax
  {$ENDIF}
end;

function EnumIPv6Card: TList<TIPv6Card>;
begin
  var
  IPv6CardList := TList<TIPv6Card>.Create;
  var
    IPv6Card: TIPv6Card;
    // 初始化 COM
  CoInitialize(nil);

  try
    // 创建 WbemLocator 实例
    var
      WbemLocator: OleVariant := CreateOleObject('WbemScripting.SWbemLocator');
      // 连接到本地 WMI 服务
    var
    WbemServices := WbemLocator.ConnectServer('.', 'root\CIMV2', '', '');

    // 执行查询：获取所有启用 IP 的网络适配器配置
    var
    WbemObjectSet := WbemServices.ExecQuery
      ('SELECT * FROM Win32_NetworkAdapterConfiguration WHERE IPEnabled = TRUE');
    var
      WbemObject: OleVariant;
    var
      Enum: IEnumVariant;
    var
      iValue: LongWord;
    var
      sName, sIP: string;
    var
      vIP: Variant;
    var
      i: integer;
      // 遍历查询结果
    Enum := IUnknown(WbemObjectSet._NewEnum) as IEnumVariant;
    while Enum.Next(1, WbemObject, iValue) = 0 do
    begin
      // 获取网卡名称（Caption）
      sName := VarToStr(WbemObject.Caption);

      // 获取 IP 地址数组
      vIP := WbemObject.IPAddress;

      // 遍历 IP 地址数组，筛选 IPv6 地址
      if VarIsArray(vIP) then
      begin
        for i := VarArrayLowBound(vIP, 1) to VarArrayHighBound(vIP, 1) do
        begin
          sIP := vIP[i];
          if Pos(':', sIP) > 0 then // IPv6 地址包含冒号
          begin
            IPv6Card.CardName := sName;
            IPv6Card.IPv6 := sIP;
            IPv6CardList.add(IPv6Card);
          end;
        end;
      end
      else if not VarIsNull(vIP) then
      begin
        sIP := vIP;
        if Pos(':', sIP) > 0 then
        begin
          IPv6Card.CardName := sName;
          IPv6Card.IPv6 := sIP;
          IPv6CardList.add(IPv6Card);
        end;
      end;
    end;
  finally
    CoUninitialize;
    Result := IPv6CardList;
  end;
end;

function HashDataCRC32(v: TIdBytes; l: int32): uint32;
begin
  if (l < 0) or (l > length(v)) then
    raise EArgumentOutOfRangeException.Create('Invalid length parameter');
  var
    D: TIdBytes;
    // 截取前len个字节
  SetLength(D, l);
  if l > 0 then
    Move(v[0], D[0], l);

  var
  hash := TIdHashCRC32.Create;
  try
    // 计算CRC32并直接转换为Cardinal（UInt32）
    Result := hash.HashValue(D);
  finally
    hash.Free;
  end;
end;

function HashDataCRC32SSE42(v: TIdBytes; l: int32): uint32;
begin
  if (l < 0) or (l > length(v)) then
    raise EArgumentOutOfRangeException.Create('Invalid length parameter');
  Result := CRC32_SSE42(v, l);
end;

function HashDataCRC32Fast(v: TIdBytes; l: int32): uint32;
begin
  if (l < 0) or (l > length(v)) then
    raise EArgumentOutOfRangeException.Create('Invalid length parameter');
  Result := CRC32_Fast(v, l);
end;

initialization

CPUFeaturesList := GetCPUFeatures;

if CPUFeaturesList.Contains('SSE4.2') then
  HashData := HashDataCRC32SSE42
else if CPUFeaturesList.Contains('PCLMUL') then
  HashData := HashDataCRC32Fast
else
  HashData := HashDataCRC32;

{
  aliveString = 'ALIVE';
  testString = 'TEST';
  fileInfoString = 'INFO';
  addString = 'ADD';
  whereString = 'WHERE';
  hashString = 'HASH';
  completeString = 'COMPLETE';
}

commandList := TStringList.Create;
commandList.add(aliveString);
commandList.add(testString);
commandList.add(fileInfoString);
commandList.add(addString);
commandList.add(whereString);
commandList.add(hashString);
commandList.add(completeString);
castCommandList := TStringList.Create;
castCommandList.add(magicString);
castCommandList.add(hashString);
castCommandList.add(atString);
castCommandList.add(readyString);

end.
